﻿namespace Dissemination.MVC.MVCContrib.Base
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using Microsoft.Practices.Unity;
    using UnityContrib.Interfaces;
    using UnityContrib.Logger;
    using Microsoft.Practices.Unity.InterceptionExtension;
    using MVCContrib.CallHandlers;
    using MVCContrib.Factories;
    using UnityContrib.Events;
    using MVCContrib.Events;

    /// <summary>
    /// 
    /// </summary>
    public class GlobalBase : HttpApplication
    {
        /// <summary>
        /// Provide hook into Application_Start from derived
        /// classes
        /// </summary>
        public event EventHandler<EventArgs> OnApplicationStart;

        /// <summary>
        /// Gets or sets the logger.
        /// </summary>
        /// <value>The logger.</value>
        public ILoggerFacade Logger { get; set; }

        private static IUnityContainer _container;
        /// <summary>
        /// Gets the container.
        /// </summary>
        /// <value>The container.</value>
        public static IUnityContainer Container
        {
            get { return _container; }
        }

        


        /// <summary>
        /// Initializes a new instance of the <see cref="GlobalBase"/> class.
        /// </summary>
        public GlobalBase()
        {
        }


        /// <summary>
        /// Application_Start that will be recognized by 
        /// system
        /// </summary>
        protected void Application_Start()
        {
            // Initialize DI Container
            InitializeContainer();

            // Intercept the Controller Factory
            InitializeInterception();
            
            // Hook for derived classes
            OnInitializeContainer();

            // Raise Application Start
            if (OnApplicationStart != null)
                OnApplicationStart(this, null);

        }

        /// <summary>
        /// Initializes the ControllerFactory interception.
        /// </summary>
        private void InitializeInterception()
        {
            // Get a reference to the current controller factory
            IControllerFactory factory =
                ControllerBuilder.Current.GetControllerFactory();

            // Configure Interception - note we register an instance of
            // the factory so that we can retrieve it in CustomerControllerFactory
            Container.AddNewExtension<Interception>()
                .RegisterInstance<IControllerFactory>(factory)
                .RegisterType<IControllerFactory,CustomControllerFactory>("Custom")
                .Configure<Interception>()
                .AddPolicy("ControllerPolicy")
                .AddMatchingRule(Container.Resolve<ControllerMatchingRule>())
                .AddCallHandler<ControllerCallHandler>();

            // Use Interface Interceptor
            Container.Configure<Interception>()
                .SetInterceptorFor<IControllerFactory>(new InterfaceInterceptor());

            // Now we'll need the factory reference (resolved by Unity) because 
            // it will be wrapped as required for interception
            IControllerFactory unityFactory = 
                Container.Resolve<IControllerFactory>("Custom");

            // Set the new ControllerFactory to the resolved factory 
            // which will be configured for interception
            ControllerBuilder.Current.SetControllerFactory(unityFactory);

        }

        /// <summary>
        /// Initializes the container.
        /// </summary>
        private void InitializeContainer()
        {
            if (_container == null)
                _container = new UnityContainer();

            // Register global types
            Container
                .RegisterType<ILoggerFacade, DebugLogger>()
                .RegisterType<IAggregatorEventTokens, AggregatorEventTokens>(
                    new ContainerControlledLifetimeManager()) // Singleton
                .RegisterType<IEventAggregator, EventAggregator>(
                    new ContainerControlledLifetimeManager()); // Singleton

            // Set logger for class use
            Logger = Container.Resolve<ILoggerFacade>();

            // Provide hook to derived class
            OnInitializeContainer();
        }


        /// <summary>
        /// Hook into InitializeContainer 
        /// </summary>
        protected virtual void OnInitializeContainer()
        {
        }
    }
}